// // EC(G)
// //  变量提升 
// //      var test
// // test=0x000
// var test = (function (i) {
//     // EC(AN) [闭包]
//     //    作用域链<EC(AN),EC(G)> 
//     //    形参赋值:i=2 ->i=4
//     //    变量提升:--   
//     return function () {
//         // EC(TEST)
//         //  作用域<EC(TEST),EC(AN)>
//         //  初始化ARGUMENTS：{0:5,length:1}实参集合
//         //  形参赋值:--
//         //  变量提升:--
//         alert(i *= 2); //"4"
//     };//return 0x000;[[scope]:EC(AN)]
// })(2);
// test(5); // return函数没有形参,5用来迷惑大家


// // EC(G)
// //      变量提升:
// //          var x;
// //          func = 0x000 [[scope]:EC(G)]
// //          var f; ->   0x001
// var x = 4;
// function func() {
//     // EC(FUNC1) [闭包]
//     //  作用域链:<EC(FUNC1,EC(G))>
//     //  形参赋值:--
//     //  变量提升:--
//     //  代码执行:
//     //   return 0x001;[[scope]:EC(FUNC1)]
//     return function(y) {
//         // EC(F1)
//         //  作用域链:<EC(F1,EC(FUNC1))>
//         //  形参赋值:y=6
//         //  变量提升:--
//         //  代码执行:
//         //      6 + 3 (x是EC(G)中的)
//         // f()第2次执行
//         // EC(F2)
//         //  作用域链:<EC(F2,EC(FUNC1))>
//         //  形参赋值:y=9
//         //  变量提升:--
//         //  代码执行:
//         //      9 + 1 (x是EC(G)中的)
//         console.log(y + (--x));
//     }

//     // ------第二次执行大函数
//     // EC(FUNC2) [闭包]
//     //  作用域链:<EC(FUNC2,EC(G))>
//     //  形参赋值:--
//     //  变量提升:--
//     //  代码执行:
//     //   return 0x002;[[scope]:EC(FUNC2)]
//     return function(y) {
//         // EC(AN)
//         //  作用域链:<EC(AN),EC(FUNC2)>
//         //  形参赋值:y=8
//         //  变量提升:--
//         //  代码执行:
//         //      8 + 2 (x是EC(G)中的)
//         console.log(y + (--x));
//     }
// }
// var f = func(5);
// f(6); //"9"
// func(7)(8); //"10"
// f(9);//"10"
// console.log(x);//"1"

// 题目6

// // EC(G)
// //  变量提升：
// //   var x; ->5 ->11 ->10
// //   var y; ->6
// //  func = 0x000; [[scope]:EC(G)]
// //       = 0x001 小函数
// var x = 5,
//     y = 6;
// function func() {
//     // EC(FUNC) ->0x001(4) [闭包]
//     //  作用域链:<EC(FUNC),EC(G)>
//     //  形参赋值:--
//     //  变量提升:--
//     x += y; // x=x+y [x和y都是EC(G)]
//     // [func也是EC(G)中的]
//     func = function (y) { //小函数:0x001 [[scope]:EC(FUNC)]
//         // EC(FUNC2) ->0x001(3)
//         //  作用域链:<EC(FUNC2),EC(FUNC)>
//         //  形参赋值:y=3
//         //  变量提升:--
//         console.log(y + (--x));//[y是私有的，x是全局的] =>13
//     };
//     console.log(x, y); //11&6
// }
// func(4); //11&6
// func(3); //=>13
// console.log(x, y); //10&6

//下面代码输出的结果是多少，为什么？如何改造一下，就能让其输出 20 10？
// var b = 10;
// (function b() { //匿名函数具名化
//     //   匿名函数具名化的特点
//     //      1.只能在函数内部使用[例如：递归]
//     //      2.如果函数内部，这个名字没有被使用其他方式声明过，那么此名字存储的是当前函数[且值不能修改]
//     //      3.但是具名化的优先级最低[一旦函数内部基于其他方式声明过这个变量，则按照私有变量处理]
//     b = 20; //如果让其输出20 在b前面加var 
//     console.log(b);//->函数
// })();
// console.log(b);//->10

// 使用函数表达式 避免变量提升
// 柯里化函数就是闭包的一种应用
// 经典的闭包应用：大函数执行，产生一个闭包，存储了第一次传递的实参信息[闭包的保存作用]
// 当小函数执行，需要用到第一次存储的这些值，直接基于作用域链的机制获取使用即可
// 所以我们可以说，闭包起到了一个“预先存储一些值的作用，供其下级上下文后期调取使用，我们把这种预先处理的思想，称之为“柯里化函数””
const fn = function (...params){
    // params是一个数组，存储的是外层函数传递的实参信息[ES6剩余运算符]
    // +鸭子函数：params = [].slice.call(arguments)
    return function proxy(...args) {
        // args是一个数组，数组中存储小函数传递的实参信息
        // + params:[1,2]
        // +args:[3]
        params = params.concat(args)
        // 数组求和1:命令式编程[关注的是过程，自己管控处理的步骤 优势:灵活 弊端:复杂冗余]
        // let total = 0;
        //     i = 0;
        //     len =params.length;
        //     for(;i<len;i++){
        //         total+=params[i]
        //     }
        // 数组求和2：函数式编程 [关注的是结果，把具体实现的步骤封装成一个函数，后期只需要执行函数即可，没必要自己去实现这个过程]
        // 优势：使用简便 弊端：无法灵活掌控 =>推荐使用函数式编程
        // let total = 0;
        // params.forEach((item,index) =>{
        //     total+=item;
        // })
        // return total;

        // 数组求和3：投机取巧 eval性能不好 不建议使用
        return eval(params.join('+'))

        // 数组求和4：reduce
        return params.reduce((total,item) =>{
            return total + item
        },0)
    }
}
let res = fn(1,2)(3)
console.log(res)

// // reduce也是用来迭代数组中每一项的，只不过，它可以把上一次处理的结果，直接传递给下一次处理，实现每一次处理的累计
// let arr = [10,20,30,40]
// // 第一次：total数组第一项，从第二项开始迭代数组
// arr.reduce((total,item,index) =>{
//     console.log(total,item,index)
//     // 10 20 1
//     // 30 30 2
//     // 60 40 3
//     // reduce的是啥，就把其当作本次处理结果，传递给下一次迭代
//     return total + item;  // =>100
// })

// // 如果reduce传递了第二个值，那么total初始值就是第二个值，数组从第一项开始迭代...
// arr.reduce(function(total,item,index){
//     console.log(total,item,index);
//     // 0 10 0;  ->10
//     // 10 20 1; ->30
//     // 30 30 2; ->60
//     // 60 40 3 ;->100
// },0)